
/*
 * $Id: utl_halt.c,v 1.3 2006-04-03 10:25:08 bacon Exp $
 */

#include <xp/sys/utl.h>
#include <xp/bas/stdarg.h>
#include <xp/bas/time.h>

static int __halt_os (int cmd, int opt, xp_va_list ap);

// TODO: errno translation....

int xp_halt (int cmd, int opt, ...)
{
	xp_va_list arg;
	int n;

	xp_va_start (arg, opt);
	n = __halt_os (cmd, opt, arg);
	xp_va_end (arg);

	return n;
}

#if defined(_WIN32)

#include <windows.h>

static int __halt_os (int cmd, int opt, xp_va_list ap)
{
	HANDLE token;
	TOKEN_PRIVILEGES priv;		
	UINT flags;
	BOOL reboot;

	if (opt & XP_HALT_TIMED) 
	{
		if (cmd == XP_HALT_RESTART) reboot = TRUE;
		else if (cmd == XP_HALT_SHUTDOWN) reboot = FALSE;
		else return -1;
	}
	else 
	{
		if (cmd == XP_HALT_POWEROFF) flags = EWX_POWEROFF;
		else if (cmd == XP_HALT_RESTART) flags = EWX_REBOOT;
		else if (cmd == XP_HALT_SHUTDOWN) flags = EWX_SHUTDOWN;
		else return -1;
	}

	if (OpenProcessToken(GetCurrentProcess(),
		TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) == FALSE) return -1;

	LookupPrivilegeValue (XP_NULL, SE_SHUTDOWN_NAME, &priv.Privileges[0].Luid);

	/* get shutdown privilege */
	priv.PrivilegeCount = 1;
	priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	if (AdjustTokenPrivileges (token, FALSE, 
		&priv, 0, (TOKEN_PRIVILEGES*)XP_NULL, 0) == FALSE) 
	{
		CloseHandle (token);
		return -1;

	}
	if (GetLastError() != ERROR_SUCCESS) 
	{
		CloseHandle (token);
		return -1;
	}

	if (opt & XP_HALT_TIMED) {
		xp_time_t timeout = xp_va_arg (ap, xp_time_t);	
		const xp_char_t* message = xp_va_arg (ap, const xp_char_t*);

		if (InitiateSystemShutdown (XP_NULL, (LPTSTR)message, 
			(DWORD)(timeout / XP_MSEC_IN_SEC), 
			((opt & XP_HALT_FORCE)? TRUE: FALSE), reboot) == FALSE) 
		{
			/* disable shutdown privilege */
			priv.Privileges[0].Attributes = 0; 
			AdjustTokenPrivileges (token, FALSE, 
				&priv, 0, (TOKEN_PRIVILEGES*)XP_NULL, 0); 
			CloseHandle (token);
			return -1;
		}
	}
	else {
		if (opt & XP_HALT_FORCE) flags |= EWX_FORCE;

#ifdef SHTDN_REASON_MINOR_MAINTENANCE
		if (ExitWindowsEx(flags,
			SHTDN_REASON_MINOR_MAINTENANCE | 
			SHTDN_REASON_FLAG_PLANNED) == FALSE) 
#else
		if (ExitWindowsEx(flags,0) == FALSE)
#endif
		{
			/* disable shutdown privilege */
			priv.Privileges[0].Attributes = 0; 
			AdjustTokenPrivileges (token, FALSE, 
				&priv, 0, (TOKEN_PRIVILEGES*)XP_NULL, 0); 
			CloseHandle (token);
			return -1;
		}
	}

	/* disable shutdown privilege */
	priv.Privileges[0].Attributes = 0; 
	AdjustTokenPrivileges (token, FALSE, 
		&priv, 0, (TOKEN_PRIVILEGES*)XP_NULL, 0); 
	CloseHandle (token);
	return 0;
}

#elif defined(__linux)

#include <unistd.h>
#include <sys/reboot.h>

static int __halt_os (int cmd, int opt, xp_va_list ap)
{
	int flags;

	if (cmd == XP_HALT_POWEROFF) flags = RB_POWER_OFF;
	else if (cmd == XP_HALT_RESTART) flags = RB_AUTOBOOT;
	else if (cmd == XP_HALT_SHUTDOWN) flags = RB_HALT_SYSTEM;
	else return -1;

	// TODO::::::
	//if ((opt & XP_HALT_FORCE) == 0) do proper shutdown..... LINUX_REBOOT_CAD_OFF???

	sync ();

	if (reboot(flags) == -1) return -1;	
	return 0;
}

#elif defined(sun)||defined(__sun)

static int __halt_os (int cmd, int opt, xp_va_list ap)
{
	/* man -S 2 uadmin */
	return -1;
}

#else

/* PLEASE IMPLEMENT __halt_os for your OS */
static int __halt_os (int cmd, int opt, xp_va_list ap)
{
	return -1;
}

#endif

